package cn.jasonone.jame.basic;

import cn.hutool.core.convert.Convert;
import cn.jasonone.jame.JameApplication;
import cn.jasonone.jame.cycle.LifeCycle;
import cn.jasonone.jame.GameScene;
import javafx.beans.value.ChangeListener;
import javafx.scene.Scene;
import javafx.stage.Stage;

/**
 * 上下文对象
 *
 * @author Jason
 * @since 1.0.0
 */
public interface GameContext<T extends LifeCycle> {
    /**
     * 得到顶级上下文对象
     *
     * @return 上下文对象
     */
    GameContext<JameApplication> getRoot();

    /**
     * 得到创建上下文的对象
     *
     * @return 源对象
     */
    T getSource();

    /**
     * 获得父上下文
     *
     * @param <E> 带有生命周期的上下文对象
     * @return 上下文对象
     */
    <E extends LifeCycle> GameContext<E> getParent();

    /**
     * 得到舞台对象
     * @return 舞台
     */
    Stage getStage();

    /**
     * 得到全局场景对象
     * @return 全局场景对象
     */
    Scene  getScene();

    /**
     * 得到游戏场景对象
     * @return 游戏场景对象
     */
    GameScene getGameScene();

    /**
     * 设置游戏场景
     * @param gameScene 游戏场景
     */
    void setGameScene(GameScene gameScene);

    /**
     * 设置值到上下文中
     *
     * @param key   键
     * @param value 值
     */
     void put(String key, Object value);

    /**
     * 添加属性监听
     * @param key 键
     * @param value 目标值
     * @param listener 监听器
     */
    void addListener(String key,Object value,Runnable listener);
    /**
     * 添加属性监听
     * @param key 键
     * @param listener 监听器
     */
     void addListener(String key, ChangeListener listener);

    /**
     * 从上下文中获取值
     *
     * @param key 键
     * @return 值
     */
    Object get(String key);

    /**
     * 从上下文中获取值,如果值不存在或为null,则返回默认值
     *
     * @param key          键
     * @param defaultValue 默认值
     * @return 值
     */
    default Object get(String key, Object defaultValue) {
        if (!hasKey(key)) {
            return defaultValue;
        }
        Object value = get(key);
        if (value == null) {
            return defaultValue;
        }
        return value;
    }

    /**
     * 从上下文中获取值,如果值不存在或为null,则返回默认值
     * @param <V>   值类型
     * @param type  值类型
     * @param key   键
     * @param defaultValue 默认值
     * @return 值
     */
    default <V> V get(Class<V> type, String key, V defaultValue){
        return Convert.convert(type,get(key,defaultValue));
    }

    /**
     * 从上下文中获取值
     *
     * @param type 值类型
     * @param key  键
     * @param <V>  值类型
     * @return 值
     */
    default <V> V get(Class<V> type, String key) {
        if (!hasKey(key)) {
            return null;
        }
        return Convert.convert(type, get(key));
    }

    /**
     * 检查指定键是否存在
     *
     * @param key 键
     * @return {@code true or false}
     */
    boolean hasKey(String key);
}
